#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <libdrizzle-2.0/drizzle_client.h>
#include <libdrizzle-2.0/drizzle_server.h>

#define error_return(ret,fmt,args...) do{printf( "[%s:%d]" fmt "\n",__FILE__,__LINE__,##args) ; return ret; } while(0)

int process_mysql(drizzle_con_st* conn,drizzle_command_t command,const char* query)
{
    printf("---------%s-----------\n",query);
    drizzle_return_t ret;
    size_t total = strlen(query) ;
    //drizzle_result_st * result = drizzle_query(conn, NULL,query,strlen(query) , &ret);
    drizzle_result_st * result=drizzle_con_command_write(conn,NULL,command,query,total,total,&ret) ;
    if (ret != DRIZZLE_RETURN_OK || result == NULL )
    {
        if(result) drizzle_result_free(result) ;
        error_return(-1,"query failed, ret:%d errno:%d ",ret,drizzle_error_code(conn->drizzle) ) ;
    }

    ret = drizzle_result_buffer(result);
    if(ret!=DRIZZLE_RETURN_OK) 
    {
        drizzle_result_free(result) ;
        error_return(-1,"result failed") ;
    }
    drizzle_column_st* column = NULL ;
    
    while ((column= drizzle_column_next(result)) != NULL)
    {
        printf("%s |",drizzle_column_name(column)) ;
    }
    printf("column end\n") ;
    
    drizzle_row_t row = NULL ;
    while ((row= drizzle_row_next(result)) != NULL)
    {
        for (int x= 0; x < drizzle_result_column_count(result); x++)
        {
            printf("%s |",row[x]) ;
        }
        printf("row end\n") ;
    }

    drizzle_result_free(result) ;
    
    return 0 ;

}

int process_client(drizzle_con_st* client,drizzle_con_st* mysql)
{
    drizzle_command_t command ;
    size_t total =0;
    drizzle_return_t ret ;
    drizzle_result_st* result = NULL ;
    const void* sql = drizzle_con_command_buffer(client,&command,&total,&ret) ;
    if(command == DRIZZLE_COMMAND_QUIT )
    {
        drizzle_con_command_buffer_free((uint8_t*)sql) ;
        error_return(-1,"client quit") ;
    }
    if(sql ==NULL ) error_return(-1,"read commnand failed ,error:%s",drizzle_error(client->drizzle) ) ;
    printf("command:%d data:%s\n",(int)command,(char*)sql) ;

    //return first
    /*
    result = drizzle_result_create(client) ;
    if(result)
    {
        if(command == DRIZZLE_COMMAND_QUERY) drizzle_result_set_column_count(result, 0);
        drizzle_result_write(client,result,true) ;
        drizzle_result_free(result) ;

    }
    */
    
    
    //forward request
    //process_mysql(mysql,command,(const char*)sql) ;
    printf("---------%s size:%d-----------\n",(const char*)sql,total);
    result=drizzle_con_command_write(mysql,NULL,command,sql,total,total,&ret) ;
    if (ret != DRIZZLE_RETURN_OK || result == NULL )
    {
        if(result) drizzle_result_free(result) ;
        //if( ret == DRIZZLE_RETURN_ERROR_CODE) return 0 ;
        error_return(-1,"query failed, ret:%d errno:%d ",ret,drizzle_error_code(mysql->drizzle) ) ;
    }

    drizzle_con_command_buffer_free((uint8_t*)sql) ;


    ret = drizzle_result_buffer(result);
    if(ret!=DRIZZLE_RETURN_OK) error_return(-1,"result failed :%s",drizzle_error(mysql->drizzle)) ;

    //return 0 ;

    //forward result
    drizzle_result_st* client_result = drizzle_result_clone(client,result) ;
    if(client_result == NULL ) 
    {
        drizzle_result_free(result) ;
        error_return(-1,"create result failed") ;
    }
    
    
    drizzle_con_set_status(client,drizzle_con_status(mysql));

    printf("options %d %d \n",result->options,client_result->options) ;

    if(drizzle_result_column_count(result) == 0 )
    {
        drizzle_result_write(client,client_result,true) ;
    }
    else
    {

    drizzle_result_write(client,client_result,false) ;

    //for(int i = 0 ; i < drizzle_result_column_count(result) ; ++i)
    while (drizzle_column_st* column= drizzle_column_next(result) )
    {
        //drizzle_column_st* column = drizzle_column_index(result,i) ;
        drizzle_column_write(client_result,column) ;
    }
    drizzle_result_set_eof(client_result, true);

    if (command == DRIZZLE_COMMAND_FIELD_LIST)
    {
        
        drizzle_result_write(client,client_result,true) ;
    }
    else
    {
    
        drizzle_result_write(client,client_result,false) ;

    //for(int j = 0 ; j < drizzle_result_row_count(result);++j)
    while (drizzle_row_t row= drizzle_row_next(result) )
    {
        //drizzle_row_t row = drizzle_row_index(result,j) ;
        size_t* field_sizes = drizzle_row_field_sizes(result) ;
        drizzle_result_calc_row_size(client_result,row,field_sizes) ;
        drizzle_row_write(client_result) ;
        for(int i = 0 ; i < drizzle_result_column_count(result) ; ++i)
        {
            size_t size = strlen(row[i]) ;
            drizzle_field_write(client_result,row[i],size,size) ;
        }
    }

    drizzle_result_write(client,client_result,true) ;
    }


    }

    drizzle_result_free(result) ;
    drizzle_result_free(client_result) ;

    return 0 ;

}


int main(int argc,char** argv)
{
    if(argc < 2 ) error_return(-1,"usage:%s sql",argv[0]) ;

    drizzle_st* drizzle= drizzle_create() ;
    if(drizzle == NULL ) error_return(-1,"init failed") ;
    drizzle_set_option(drizzle,DRIZZLE_FREE_OBJECTS,true) ;
    //drizzle_set_option(drizzle, DRIZZLE_NON_BLOCKING, true);
    drizzle_con_st *conn= drizzle_con_add_tcp(drizzle,"192.168.78.10", 3306, "root", "", "knight_lianyun", DRIZZLE_CON_MYSQL);
    if(conn == NULL ) error_return(-1,"create conn failed") ;
    
    process_mysql(conn,DRIZZLE_COMMAND_QUERY,"set names utf8") ;
    for(int i = 0 ; i<10 ; ++i) process_mysql(conn,DRIZZLE_COMMAND_QUERY,argv[1]) ;

    printf("listen\n") ;
    //as server
    drizzle_con_st* listen_con = drizzle_con_add_tcp_listen(drizzle,"0.0.0.0",3307,10,DRIZZLE_CON_MYSQL) ;
    drizzle_con_listen(listen_con) ;

    drizzle_return_t ret ;
    drizzle_con_st* client_con = drizzle_con_accept(drizzle,&ret) ;
    if(client_con == NULL ) error_return(-1,"accept failed") ;

    drizzle_con_copy_handshake(client_con,conn) ;
    if(drizzle_handshake_server_write(client_con)!= DRIZZLE_RETURN_OK ) error_return(-1,"handshake failed") ;
    if(drizzle_handshake_client_read(client_con)!=DRIZZLE_RETURN_OK) error_return(-1,"read failed") ;
    drizzle_result_st* result = drizzle_result_create(client_con) ;
    if(result==NULL) error_return(-1,"result failed") ;
    drizzle_result_write(client_con,result,true) ;
    drizzle_result_free(result) ;

    while( process_client(client_con,conn)==0 )  ;
    

    drizzle_free(drizzle) ;
    return 0 ;

}

